package com.friends.utils.excel.easyexcel3.handler;

import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.List;

/**
 * 上下行相同 进行合并
 */
public class ExcelMergeHandler implements CellWriteHandler {
 
    /**
     * 需要合并列的下标，从0开始
     * 示例
     *  EasyExcel.write(response.getOutputStream(), T.class)
     *                     .registerWriteHandler(new CustomCellWriteHandler())
     *                     .registerWriteHandler(new ExcelMergeHandler(1, new int[]{0,1,2,3,4,7}))
     *                     .sheet(ExcelExportConstants.WAIT)
     *                     .doWrite(exportList);
     */
    private int[] mergeColumnIndex;
    /**
     * 从第几行开始合并，表头下标为0
     */
    private int mergeRowIndex;
 
    public ExcelMergeHandler(int mergeRowIndex, int[] mergeColumnIndex) {
        this.mergeRowIndex = mergeRowIndex;
        this.mergeColumnIndex = mergeColumnIndex;
    }
 
    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {
 
    }
 
    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {
 
    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        //当前行
        int curRowIndex = cell.getRowIndex();
        //当前列
        int curColIndex = cell.getColumnIndex();

        if (curRowIndex > mergeRowIndex) {
            for (int i = 0; i < mergeColumnIndex.length; i++) {
                if (curColIndex == mergeColumnIndex[i]) {
                    mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
                    break;
                }
            }
        }
    }
 
 
    private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
        /*62行-81行为重写的逻辑，业务场景：比如一个单据导出，多张单据中的某个字段是相同的，但是合并我们要按照单据合并，所以增加自己的判断逻辑*/
        // 上一行
        Row preRow = cell.getSheet().getRow(curRowIndex - 1);
        // 如果当前列大于等于第二列
        if (curColIndex >= 1) {
            // 当前行
            Row curRow = cell.getSheet().getRow(curRowIndex);
            // 获取当前行和上一行的流程编号
            Cell curOaFlowCell = curRow.getCell(1);
            Cell preOaFlowCell = preRow.getCell(1);
            Object curOaFlowData = curOaFlowCell.getCellTypeEnum() == CellType.STRING ? curOaFlowCell.getStringCellValue() :
                    curOaFlowCell.getNumericCellValue();
            Object preOaFlowData = preOaFlowCell.getCellTypeEnum() == CellType.STRING ? preOaFlowCell.getStringCellValue() :
                    preOaFlowCell.getNumericCellValue();
            // 上一行编号和当前行编号不相等
            if (!preOaFlowData.equals(curOaFlowData)) {
                // 不进行合并
                return;
            }
        }
        //获取当前行的当前列的数据和上一行的当前列列数据，通过上一行数据是否相同进行合并
        Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() :
                cell.getNumericCellValue();
        if (preRow == null) {
            // 当获取不到上一行数据时，使用缓存sheet中数据
            preRow = writeSheetHolder.getCachedSheet().getRow(curRowIndex - 1);
        }
        Cell preCell = preRow.getCell(curColIndex);
        Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() :
                preCell.getNumericCellValue();
        // 比较当前行的第一列的单元格与上一行是否相同，相同合并当前单元格与上一行
        if (curData.equals(preData)) {
            Sheet sheet = writeSheetHolder.getSheet();
            List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
            boolean isMerged = false;
            for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
                CellRangeAddress cellRangeAddr = mergeRegions.get(i);
                // 若上一个单元格已经被合并，则先移出原有的合并单元，再重新添加合并单元
                if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
                    sheet.removeMergedRegion(i);
                    cellRangeAddr.setLastRow(curRowIndex);
                    sheet.addMergedRegion(cellRangeAddr);
                    isMerged = true;
                }
            }
            // 若上一个单元格未被合并，则新增合并单元
            if (!isMerged) {
                CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex,
                        curColIndex);
                sheet.addMergedRegion(cellRangeAddress);
            }
        }
    }
}